﻿using System;
using System.IO;

namespace Rosetta.Default
{
    public abstract class Outputter : AddIn, IOutputter
    {
        #region Constructors

        protected Outputter(string name)
            : base(name, Validate)
        {
        }

        #endregion

        #region Properties

        [NotNull]
        public Type[] ArgumentTypes
        {
            get
            {
                return ArgumentTypesInternal;
            }
        }

        [CanBeNull]
        public TextWriter Log { get; set; }

        #endregion

        #region Public Methods

        public Action<T> Put<T>(string methodName)
        {
            return (Action<T>)this[methodName];
        }

        public Action<T1, T2> Put<T1, T2>(string methodName)
        {
            return (Action<T1, T2>)this[methodName];
        }

        public Action<T1, T2, T3> Put<T1, T2, T3>(string methodName)
        {
            return (Action<T1, T2, T3>)this[methodName];
        }

        public Action<T1, T2, T3, T4> Put<T1, T2, T3, T4>(string methodName)
        {
            return (Action<T1, T2, T3, T4>)this[methodName];
        }

        #endregion

        #region Protected Methods

        protected void Add<T>(string methodName, Action<T> action, params string[] argumentNames)
        {
            AddMethod(methodName, action, argumentNames);
        }

        protected void Add<T1, T2>(string methodName, Action<T1, T2> action, params string[] argumentNames)
        {
            AddMethod(methodName, action, argumentNames);
        }

        protected void Add<T1, T2, T3>(string methodName, Action<T1, T2, T3> action, params string[] argumentNames)
        {
            AddMethod(methodName, action, argumentNames);
        }

        protected void Add<T1, T2, T3, T4>(string methodName, Action<T1, T2, T3, T4> action, params string[] argumentNames)
        {
            AddMethod(methodName, action, argumentNames);
        }

        protected void Write(string value)
        {
            var log = Log;
            if (log != null)
            {
                log.Write(value);
            }
        }

        protected void WriteLine(string value)
        {
            var log = Log;
            if (log != null)
            {
                log.WriteLine(value);
            }
        }

        #endregion

        #region Class Methods

        private static bool Validate(Delegate handler)
        {
            if (handler != null)
            {
                var type = handler.GetType();
                if (type.IsGenericType)
                {
                    return IsActionType(type.GetGenericTypeDefinition());
                }
            }
            return false;
        }

        #endregion
    }
}